package com.imooc.activitiweb.controller;

import com.imooc.activitiweb.SecurityUtil;
import com.imooc.activitiweb.pojo.UserInfoBean;
import com.imooc.activitiweb.util.AjaxResponse;
import com.imooc.activitiweb.util.CreateMap;
import com.imooc.activitiweb.util.GlobalConfig;
import org.activiti.api.model.shared.model.VariableInstance;
import org.activiti.api.process.model.ProcessInstance;
import org.activiti.api.process.model.builders.ProcessPayloadBuilder;
import org.activiti.api.process.runtime.ProcessRuntime;
import org.activiti.api.runtime.shared.query.Page;
import org.activiti.api.runtime.shared.query.Pageable;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.ProcessDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 流程实例 控制类
 */
@RestController
@RequestMapping("/processInstance")
public class ProcessInstanceController {

    // 自己定义的 SecurityUtil 使用 activity 新特性需要登录
    @Autowired
    private SecurityUtil securityUtil;
    @Autowired
    private ProcessRuntime processRuntime;
    @Autowired
    private RepositoryService repositoryService;
    /**
     * 获取流程实例列表
     * @AuthenticationPrincipal 注解可以获取用于登录信息
     * @param userInfoBean
     * @return
     */
    @GetMapping("/getInstances")
    public AjaxResponse getInstance(@AuthenticationPrincipal UserInfoBean userInfoBean){

        try{
            // 这是 GlobalConfig 类定义的是否是测试标记，标记是测试环境使用 内存用户登录，方便测试使用
            if(GlobalConfig.Test){
                // 测试环境使用内存用户登录
                securityUtil.logInAs("zhangsan");
            }
            // 获取流程实例
            Page<ProcessInstance> processInstancePage = processRuntime.processInstances(Pageable.of(0, 100));
            // 将流程实例转换为 list
            List<ProcessInstance> lists = processInstancePage.getContent();
            // 对 list 进行排序  按照启动日期排序
            lists.sort((x,y) -> y.getStartDate().toString().compareTo(x.getStartDate().toString()));
            // 创建 map 保存流程实例列表
            List<Map<String,Object>> listMap = new ArrayList<Map<String, Object>>();
            for(ProcessInstance pi : lists){
                // 因为 ProcessInstance 中没有历史高亮需要的 deploymentID 和 资源 resourceName ,所以需要查询
                ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                        .processDefinitionId(pi.getProcessDefinitionId())
                        .singleResult();

                listMap.add(new CreateMap.Build()
                        .setAttribute("id",pi.getId())
                        .setAttribute("name",pi.getName())
                        .setAttribute("status",pi.getStatus())
                        .setAttribute("processDefinitionId",pi.getProcessDefinitionId())
                        .setAttribute("processDefinitionKey",pi.getProcessDefinitionKey())
                        .setAttribute("startDate",pi.getStartDate())
                        .setAttribute("processDefinitionVersion", pi.getProcessDefinitionVersion())
                        .setAttribute("deploymentId", processDefinition.getDeploymentId())
                        .setAttribute("resourceName",processDefinition.getResourceName())
                        .build());
            }
            return AjaxResponse.AjaxData(
                    GlobalConfig.ResponseCode.SUCCESS.getCode(),
                    GlobalConfig.ResponseCode.SUCCESS.getDesc(),
                    listMap
            );
        }catch (Exception e){
            return AjaxResponse.AjaxData(
                    GlobalConfig.ResponseCode.ERROR.getCode(),
                    "获取流程实例列表失败",
                    e.toString()
            );
        }
    }


    /**
     * 启动流程实例
     * @param processDefinitionKey   流程定义 key
     * @param instanceName            流程实例名称
     * @return
     */
    @GetMapping("/startProcess")
    public AjaxResponse startProcess(@RequestParam("processDefinitionKey")String processDefinitionKey,
                                     @RequestParam("instanceName")String instanceName,
                                     @AuthenticationPrincipal UserInfoBean userInfoBean){
        try{
            // 测试环境使用内容用户登录
            if(GlobalConfig.Test){
                securityUtil.logInAs("zhangsan");
            }else{
                 // 这样也可以获取到登录人
                // securityUtil.logInAs(SecurityContextHolder.getContext().getAuthentication().getName());
            }
            ProcessInstance processInstance = processRuntime.start(
                    ProcessPayloadBuilder
                            .start()
                            .withProcessDefinitionKey(processDefinitionKey)
                            .withName(instanceName)
                            .withBusinessKey("自定义业务key")
                           // .withVariable("参数name", "参数值")  启动一般不加参数，业务生成是才加参数
                            .build()
            );
                return AjaxResponse.AjaxData(
                        GlobalConfig.ResponseCode.SUCCESS.getCode(),
                        GlobalConfig.ResponseCode.SUCCESS.getDesc(),
                        null
                );
        }catch (Exception e){
            return AjaxResponse.AjaxData(
                    GlobalConfig.ResponseCode.ERROR.getCode(),
                    "启动流程实例失败",
                    e.toString()
            );
        }
    }

    // 挂起流程实例
    // 一般使用场景是：流程实例运行过程中，用户觉得流程需要暂停，但是又不想删除它，需要将历史保留起来，
    // 这个时候需要使用挂起了

    /**
     * 挂起流程实例
     * @param instanceId  实例 id
     * @return
     */
    @GetMapping("/suspendInstance")
    public AjaxResponse suspendInstance(@RequestParam("instanceId")String instanceId){
        try{
            // 测试环境使用内容用户登录
            if(GlobalConfig.Test){
                securityUtil.logInAs("zhangsan");
            }
            ProcessInstance processInstance = processRuntime.suspend(
                    ProcessPayloadBuilder
                            .suspend()
                            .withProcessInstanceId(instanceId)
                            .build()
            );

            return AjaxResponse.AjaxData(
                    GlobalConfig.ResponseCode.SUCCESS.getCode(),
                    GlobalConfig.ResponseCode.SUCCESS.getDesc(),
                    processInstance.getName()  // 返回实例名称
            );
        }catch (Exception e){
            return AjaxResponse.AjaxData(
                    GlobalConfig.ResponseCode.ERROR.getCode(),
                    "挂起暂停流程实例失败",
                    e.toString()
            );
        }
    }

    /**
     * 恢复流程实例
     * @param instanceId  实例 id
     * @return
     */
    @GetMapping("/resumeInstance")
    public AjaxResponse resumeInstance(@RequestParam("instanceId")String instanceId){
        try{
            // 测试环境使用内容用户登录
            if(GlobalConfig.Test){
                securityUtil.logInAs("zhangsan");
            }
            ProcessInstance processInstance = processRuntime.resume(
                    ProcessPayloadBuilder
                            .resume()
                            .withProcessInstanceId(instanceId)
                            .build()
            );

            return AjaxResponse.AjaxData(
                    GlobalConfig.ResponseCode.SUCCESS.getCode(),
                    GlobalConfig.ResponseCode.SUCCESS.getDesc(),
                    processInstance.getName()  // 返回实例名称
            );
        }catch (Exception e){
            return AjaxResponse.AjaxData(
                    GlobalConfig.ResponseCode.ERROR.getCode(),
                    "恢复流程实例失败",
                    e.toString()
            );
        }
    }

    /**
     * 删除流程实例
     * @param instanceId  实例 id
     * @return
     */
    @GetMapping("/deleteInstance")
    public AjaxResponse deleteInstance(@RequestParam("instanceId")String instanceId){
        try{
            // 测试环境使用内容用户登录
            if(GlobalConfig.Test){
                securityUtil.logInAs("zhangsan");
            }
            ProcessInstance processInstance = processRuntime.delete(
                    ProcessPayloadBuilder
                            .delete()
                            .withProcessInstanceId(instanceId)
                            .build()
            );

            return AjaxResponse.AjaxData(
                    GlobalConfig.ResponseCode.SUCCESS.getCode(),
                    GlobalConfig.ResponseCode.SUCCESS.getDesc(),
                    processInstance.getName()  // 返回实例名称
            );
        }catch (Exception e){
            return AjaxResponse.AjaxData(
                    GlobalConfig.ResponseCode.ERROR.getCode(),
                    "删除流程实例失败",
                    e.toString()
            );
        }
    }

    /**
     * 查询流程实例参数
     * @param instanceId  实例 id
     * @return
     */
    @GetMapping("/variables")
    public AjaxResponse variables(@RequestParam("instanceId")String instanceId){
        try{
            // 测试环境使用内容用户登录
            if(GlobalConfig.Test){
                securityUtil.logInAs("zhangsan");
            }
            List<VariableInstance> variables = processRuntime.variables(
                    ProcessPayloadBuilder
                            .variables()
                            .withProcessInstanceId(instanceId)
                            .build()
            );

            return AjaxResponse.AjaxData(
                    GlobalConfig.ResponseCode.SUCCESS.getCode(),
                    GlobalConfig.ResponseCode.SUCCESS.getDesc(),
                    variables  // 返回流程参数列表
            );
        }catch (Exception e){
            return AjaxResponse.AjaxData(
                    GlobalConfig.ResponseCode.ERROR.getCode(),
                    "查询流程实例参数失败",
                    e.toString()
            );
        }
    }
}
